import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from numpy import trapz
from sklearn.preprocessing import minmax_scale
import traceback

desired_width = 320
pd.set_option('display.width', desired_width)
pd.set_option('display.max_columns', 20)
pd.set_option('display.max_rows', 200)
np.set_printoptions(linewidth=desired_width)


def sigmoid(x, derivative=False):
    x = 100 * x
    return x * (1 - x) if derivative else 1 / (1 + np.exp((-x)))


def convert_return(row, predict_colname):
    col_value = row[predict_colname]
    if col_value > 0:
        return sigmoid(col_value)
    elif col_value <= 0:
        return sigmoid(-col_value)


def plt_roc(area, title, x_label, x_value, y_label, y_value):
    plt.figure(figsize=(20, 20))
    plt.plot(x_value, y_value, label='AUC %.3f' % area)
    plt.plot([0, 1], [0, 1], 'k--', lw=1)
    plt.title(title)
    plt.xlabel(x_label)
    plt.ylabel(y_label)
    plt.xlim(0, 1)
    plt.ylim(0, 1)
    plt.legend(loc="upper left")
    plt.grid()
    plt.show()


def stand_auc(df, positive_return=True, from_origin_price_file=False):
    if from_origin_price_file:
        price_header = 'close'
        df['return'] = np.log10(df[price_header].shift(-1440) / df[price_header].shift(-1))

    df = df.reindex(abs(df['return']).sort_values(ascending=False).index).copy()
    df['return_sigmoid'] = df.apply(lambda row: convert_return(row, 'return'), axis=1)

    if positive_return:
        df = df.loc[df['return'] >= 0].copy()
    else:
        df = df.loc[df['return'] < 0].copy()
    df.reset_index(inplace=True, drop=True)

    df['return_sigmoid_cumsum'] = df['return_sigmoid'].cumsum()

    x_value = minmax_scale(range(0, len(df)))
    y_value = minmax_scale(np.array(df['return_sigmoid_cumsum']))
    area = trapz(y_value, x_value)

    title = 'positive best' if positive_return else 'negative best'
    plt.figure(figsize=(10, 10))
    plt.plot(x_value, y_value, label='AUC %.3f' % area)
    plt.plot([0, 1], [0, 1], 'k--', lw=1)
    plt.plot(x_value, df['return'], 'r', )
    plt.plot(x_value, df['return_sigmoid'], 'g')
    plt.title(title)
    plt.xlabel('return descend order')
    plt.ylabel('sigmoid( true return ) cumsum')
    plt.legend(loc="upper left")
    plt.grid()
    # plt.show()


def auc_return_sigmoid(df, model_name='xgboost', predict_positive=True, plot=False, manual_correction=False):
    try:
        predict_sort_df = df.reindex(abs(df[model_name]).sort_values(ascending=False).index).copy()
        if predict_positive:
            predict_sort_df = predict_sort_df[predict_sort_df[model_name] >= 0]
        else:
            predict_sort_df = predict_sort_df[predict_sort_df[model_name] < 0]
        if len(predict_sort_df) == 0:
            return 0, pd.DataFrame()
        change_end_index = int(len(predict_sort_df) * 0.1)
        if manual_correction:
            predict_sort_df.reset_index(inplace=True, drop=True)
            # series_mean = predict_sort_df['return'].mean()
            series_mean = 0
            new_column = pd.Series([series_mean] * change_end_index, name=model_name)
            predict_sort_df.update(new_column)
            predict_sort_df.sort_values(model_name, inplace=True)
        predict_sort_df['return_sigmoid'] = predict_sort_df.apply(lambda row: convert_return(row, 'return'), axis=1)
        predict_sort_df['return_sigmoid_cumsum'] = abs(predict_sort_df['return_sigmoid']).cumsum()

        x_value = minmax_scale(range(0, len(predict_sort_df)))
        y_value = minmax_scale(np.array(predict_sort_df['return_sigmoid_cumsum']))
        # true_return = minmax_scale(np.array(predict_sort_df['return']), feature_range=(-0.2, 0.0))
        true_return = predict_sort_df['return']
        area = trapz(y_value, x_value)
        y_value_sum = y_value[:change_end_index].sum()
        if plot:
            plt.figure(figsize=(10, 10))
            if predict_positive:
                plt.title('predict >= 0')
            else:
                plt.title('predict < 0')
            plt.xlabel('predict return')
            plt.ylabel('sigmoid( true return ) cumsum')

            plt.plot(x_value, y_value, label='AUC %.3f' % area)
            plt.plot([0, 1], [0, 1], 'k--', lw=1)
            plt.plot(x_value, true_return, 'r', lw=1, label='true return, axis=x top 10%% sum=%.3f' % y_value_sum)
            plt.legend(loc="upper left")
            plt.grid()
        return round(area, 6), predict_sort_df
    except Exception as e:
        traceback.print_exc()
        return 0, pd.DataFrame()


def auc_return_abs_positive(df, predict_colname):
    predict_sort_df = df.reindex(abs(df[predict_colname]).sort_values(ascending=False).index).copy()

    tmp_df = predict_sort_df.loc[predict_sort_df[predict_colname] >= 0].copy()
    tmp_df['abs_cumsum'] = abs(tmp_df['return']).cumsum()
    tmp_df['abs_cumsum'] /= max(tmp_df['abs_cumsum'])

    x_value = np.hstack([0, range(1, len(tmp_df) + 1)])
    y_value = np.hstack([0, tmp_df['abs_cumsum']])
    x_value = minmax_scale(x_value)
    y_value = minmax_scale(y_value)

    area = trapz(y_value, x_value)
    return area, tmp_df


def auc_return_abs_negative(df, predict_colname, plot=False):
    predict_sort_df = df.reindex(abs(df[predict_colname]).sort_values(ascending=False).index).copy()
    tmp_df = predict_sort_df.loc[predict_sort_df[predict_colname] < 0].copy()

    tmp_df['return_abs_cumsum'] = (-tmp_df['return']).cumsum()
    tmp_df.fillna(0, inplace=True)
    tmp_df['return_abs_cumsum'] /= max(tmp_df['return_abs_cumsum'])

    x_value = np.hstack([0, range(1, len(tmp_df) + 1)])
    y_value = np.hstack([0, tmp_df['return_abs_cumsum']])
    x_value = minmax_scale(x_value)
    y_value = minmax_scale(y_value)

    area = trapz(y_value, x_value)

    if plot:
        title = 'return < 0, return log, best.'
        x_label = 'predict return'
        y_label = 'sigmoid( true return ) cumsum'
        plt_roc(area, title, x_label, x_value, y_label, y_value)


def volatility_auc(df, result_column_name):
    df.dropna(inplace=True)
    predict_sort_df = df.reindex(abs(df[result_column_name]).sort_values(ascending=False).index).copy()
    predict_sort_df['volatility_cumsum'] = abs(predict_sort_df['volatility']).cumsum()
    predict_sort_df.fillna(0, inplace=True)
    predict_sort_df['volatility_cumsum'] /= max(predict_sort_df['volatility_cumsum'])

    x_value = np.hstack([0, range(1, len(predict_sort_df) + 1)])
    y_value = np.hstack([0, predict_sort_df['volatility_cumsum']])
    x_value = minmax_scale(x_value)
    y_value = minmax_scale(y_value)
    area = trapz(y_value, x_value)
    return area


if __name__ == '__main__':
    # df = pd.read_csv('/Users/liujingjun/work/ml/bitcoin-predict/data/result/online/predict-return-1001-1118.csv')
    # df.dropna(inplace=True)
    # df = df[::60]
    # print(df.corr())
    # print(df.head())
    # auc_return_sigmoid(df, 'xgboost', predict_positive=False, plot=True, manual_correction=False)

    df = pd.read_csv('./data/result/timeline/xgboost_predict_result_0904-1206.csv')
    auc_return_sigmoid(df, 'predict_return', predict_positive=True, plot=True, manual_correction=False)
    auc_return_sigmoid(df, 'predict_return', predict_positive=False, plot=True, manual_correction=False)

    # df = pd.read_csv('./data/result/online/predict-return-06-11.csv')
    # df = df[::60]
    # df = pd.read_csv('./data/result/online/predict-return-06-11-gblinear.csv')
    # df = pd.read_csv('./model/predict-return-1001-1118.csv')
    # df = pd.read_csv('./data/result/lstm-xgboost-predict_result.csv')

    # df = pd.read_csv('./model/predict-return-1001-1118.csv')
    # df = df[::60]
    # auc_return_sigmoid(df, 'xgboost', predict_positive=False, plot=True, manual_correction=False)

    # df = pd.read_csv('./data/result/lstm-predict_result.csv')
    # auc_return_sigmoid(df, 'predict_return', predict_positive=False, plot=True, manual_correction=False)

    # area, roc_df = auc_return_sigmoid(df, 'predict_return', True, True)
    # print(area)
    # print(roc_df)

    # df = pd.read_csv('./data/result/online/predict-volatility-06-11.csv')
    # volatility_auc(df, 'xgboost')

    # df = pd.read_csv('./data/result/lstm-predict_result.csv')

    df = pd.read_csv('./data/result/timeline/xgboost_predict_result_0904-1206.csv')
    stand_auc(df, positive_return=False)
    stand_auc(df, positive_return=True)
    plt.show()
    pass
